package com.lej.core.utils.extention


import android.annotation.SuppressLint
import android.util.SparseIntArray
import android.view.ViewGroup
import androidx.annotation.IntDef
import androidx.annotation.LayoutRes
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.module.LoadMoreModule
import com.chad.library.adapter.base.module.UpFetchModule
import com.chad.library.adapter.base.viewholder.BaseViewHolder

typealias AreSame<T> = ((oldItem: T, newItem: T) -> Boolean)?

fun <T> RecyclerView.generateQ(
    res: Int,
    areContentsTheSame: AreSame<T> = null,
    areItemsTheSame: AreSame<T> = null,
    @LoadType
    loadType: Int = LOAD_TYPE_NONE,
    convert: ((helper: BaseViewHolder, item: T?) -> Unit)? = null
): QuickAdapter<T> {
    val callback = object : DiffUtil.ItemCallback<T>() {
        ///是否同一个item
        override fun areItemsTheSame(oldItem: T, newItem: T): Boolean =
            areItemsTheSame?.invoke(oldItem, newItem) ?: true

        @SuppressLint("DiffUtilEquals")
        ///是否展示内容相同
        override fun areContentsTheSame(oldItem: T, newItem: T): Boolean =
            (areContentsTheSame?.invoke(oldItem, newItem) ?: oldItem) == newItem
    }

    open class InnerAdapter : QuickAdapter<T>(res) {
        override fun onItemViewHolderCreated(viewHolder: BaseViewHolder, viewType: Int) {
            DataBindingUtil.bind<ViewDataBinding>(viewHolder.itemView)
        }

        override fun convert(holder: BaseViewHolder, item: T) {
            convert?.invoke(holder, item)
        }
    }

    val adapter = when (loadType) {
        LOAD_TYPE_LOAD_MORE -> object : InnerAdapter(), LoadMoreModule {}
        LOAD_TYPE_UP_FETCH -> object : InnerAdapter(), UpFetchModule {}
        LOAD_TYPE_UP_AND_LOAD -> object : InnerAdapter(), LoadMoreModule, UpFetchModule {}
        else -> object : InnerAdapter() {}
    }
    adapter.setDiffCallback(callback)
    this.adapter = adapter
    return adapter
}

abstract class QuickAdapter<T>(var res: Int) : BaseQuickAdapter<T, BaseViewHolder>(res)

inline fun <reified T : ViewDataBinding> BaseViewHolder.getBind(): T? =
    DataBindingUtil.bind<ViewDataBinding>(itemView) as? T

const val LOAD_TYPE_NONE = 0x00
const val LOAD_TYPE_LOAD_MORE = 0x01
const val LOAD_TYPE_UP_FETCH = 0x10
const val LOAD_TYPE_UP_AND_LOAD = 0x11

@IntDef(value = [LOAD_TYPE_NONE, LOAD_TYPE_LOAD_MORE, LOAD_TYPE_UP_FETCH, LOAD_TYPE_UP_AND_LOAD])
@Retention(value = AnnotationRetention.SOURCE)
annotation class LoadType


open class MultiHolder<T>(val resId: Int, val type: Int, val convert: ((holder: BaseViewHolder, item: T?) -> Unit)? = null)

fun <T> RecyclerView.generateMultiQHolder(vararg vh: MultiHolder<T>, getType: (item: T) -> Int, loadType: Int = LOAD_TYPE_NONE): QuickMultiAdapter<T> {
    val holderMap = hashMapOf<Int, MultiHolder<T>>()
    val types = hashMapOf<Int, Int>()
    vh.forEach {
        holderMap[it.type] = it
        types[it.type] = it.resId
    }
    return generateMultiQ(types, getType = getType, loadType = loadType, convert = { helper: BaseViewHolder, item: T? ->
        if (item == null) return@generateMultiQ
        val type = getType(item)
        holderMap[type]?.convert?.invoke(helper, item)
    })
}

/**[types]  type to layoutRes [loadType] 0没有 1 向下加载更多 2 向上加载更多 3 一起加载更多*/
fun <T> RecyclerView.generateMultiQ(
    types: HashMap<Int, Int>,
    getType: (item: T) -> Int,
    areContentsTheSame: AreSame<T> = null,
    areItemsTheSame: AreSame<T> = null,
    @LoadType
    loadType: Int = LOAD_TYPE_NONE,
    convert: ((helper: BaseViewHolder, item: T?) -> Unit)? = null
): QuickMultiAdapter<T> {
    val callback = object : DiffUtil.ItemCallback<T>() {
        ///是否同一个item
        override fun areItemsTheSame(oldItem: T, newItem: T): Boolean =
            (areItemsTheSame?.invoke(oldItem, newItem) ?: getType(oldItem)) == getType(newItem)

        @SuppressLint("DiffUtilEquals")
        ///是否展示内容相同
        override fun areContentsTheSame(oldItem: T, newItem: T): Boolean =
            (areContentsTheSame?.invoke(oldItem, newItem) ?: oldItem) == newItem
    }

    open class InnerAdapter : QuickMultiAdapter<T>(getType = getType) {
        init {
            types.forEach { addItemType(it.key, it.value) }
        }

        override fun convert(holder: BaseViewHolder, item: T) {
            convert?.invoke(holder, item)
        }
    }

    val adapter = when (loadType) {
        LOAD_TYPE_LOAD_MORE -> object : InnerAdapter(), LoadMoreModule {}
        LOAD_TYPE_UP_FETCH -> object : InnerAdapter(), UpFetchModule {}
        LOAD_TYPE_UP_AND_LOAD -> object : InnerAdapter(), LoadMoreModule, UpFetchModule {}
        else -> object : InnerAdapter() {}
    }
    adapter.setDiffCallback(callback)
    this.adapter = adapter
    return adapter
}

abstract class QuickMultiAdapter<T>(val getType: (item: T) -> Int) : BaseQuickAdapter<T, BaseViewHolder>(0) {

    private val layouts: SparseIntArray by lazy(LazyThreadSafetyMode.NONE) { SparseIntArray() }

    override fun getDefItemViewType(position: Int): Int = getType(data[position])

    override fun onCreateDefViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
        val layoutResId = layouts.get(viewType)
        require(layoutResId != 0) { "ViewType: $viewType found layoutResId，please use addItemType() first!" }
        return createBaseViewHolder(parent, layoutResId)
    }

    /**
     * 调用此方法，设置多布局
     * @param type Int
     * @param layoutResId Int
     */
    protected fun addItemType(type: Int, @LayoutRes layoutResId: Int) {
        layouts.put(type, layoutResId)
    }
}